
<!DOCTYPE html>
<!--[if IEMobile 7 ]><html class="no-js iem7"><![endif]-->
<!--[if lt IE 9]><html class="no-js lte-ie8"><![endif]-->
<!--[if (gt IE 8)|(gt IEMobile 7)|!(IEMobile)|!(IE)]><!--><html class="no-js" lang="en"><!--<![endif]-->
<head>
  <meta charset="utf-8">
  <title>诡异的程序性能问题 - Yebangyu's Blog</title>
  <meta name="author" content="Yebangyu">

  
  <meta name="description" content="并行编程 false sharing 高并发 多线程">
  <meta name="keywords" content="并行编程 false sharing 高并发 多线程">

  <!-- http://t.co/dKP3o1e -->
  <meta name="HandheldFriendly" content="True">
  <meta name="MobileOptimized" content="320">
  <meta name="viewport" content="width=device-width, initial-scale=1">

  
  <link rel="canonical" href="http://www.yebangyu.org/blog/2015/12/30/falsesharing/">
  <link href="/favicon.png" rel="icon">
  <link href="/stylesheets/screen.css" media="screen, projection" rel="stylesheet" type="text/css">
  <link href="/atom.xml" rel="alternate" title="Yebangyu's Blog" type="application/atom+xml">
  <script src="/javascripts/modernizr-2.0.js"></script>
  <script src="//ajax.lug.ustc.edu.cn/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
  <script>!window.jQuery && document.write(unescape('%3Cscript src="/javascripts/libs/jquery.min.js"%3E%3C/script%3E'))</script>
  <script src="/javascripts/octopress.js" type="text/javascript"></script>
  <!--Fonts from Google"s Web font directory at http://google.com/webfonts -->
<link href="//fonts.lug.ustc.edu.cn/css?family=PT+Serif:regular,italic,bold,bolditalic" rel="stylesheet" type="text/css">
<link href="//fonts.lug.ustc.edu.cn/css?family=PT+Sans:regular,italic,bold,bolditalic" rel="stylesheet" type="text/css">
<!-- mathjax config similar to math.stackexchange -->
<script type="text/x-mathjax-config">
MathJax.Hub.Config({
  jax: ["input/TeX", "output/HTML-CSS"],
  tex2jax: {
    inlineMath: [ ['$', '$'] ],
    displayMath: [ ['$$', '$$']],
    processEscapes: true,
    skipTags: ['script', 'noscript', 'style', 'textarea', 'pre', 'code']
  },
  messageStyle: "none",
  "HTML-CSS": { preferredFont: "TeX", availableFonts: ["STIX","TeX"] }
});
</script>
<script src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_HTML" type="text/javascript"></script>

  

</head>

<body   >
  <header role="banner"><hgroup>
  <h1><a href="/">Yebangyu's Blog</a></h1>
  
    <h2>Fond of Concurrency Programming and Machine Learning</h2>
  
</hgroup>

</header>
  <nav role="navigation"><ul class="subscription" data-subscription="rss">
  <li><a href="/atom.xml" rel="subscribe-rss" title="subscribe via RSS">RSS</a></li>
  
</ul>
  
<form action="https://www.google.com/search" method="get">
  <fieldset role="search">
    <input type="hidden" name="sitesearch" value="www.yebangyu.org">
    <input class="search" type="text" name="q" results="0" placeholder="Search"/>
  </fieldset>
</form>
  
<ul class="main-navigation">
  <li><a href="/">Blog</a></li>
  <li><a href="/blog/archives">Archives</a></li>
  <li><a href="/about">About Me</a></li>
</ul>

</nav>
  <div id="main">
    <div id="content">
      <div>
<article class="hentry" role="article">
  
  <header>
    
      <h1 class="entry-title">诡异的程序性能问题</h1>
    
    
      <p class="meta">
        




<time class='entry-date' datetime='2015-12-30T23:06:12+08:00'><span class='date'><span class='date-month'>Dec</span> <span class='date-day'>30</span><span class='date-suffix'>th</span>, <span class='date-year'>2015</span></span> <span class='time'>11:06 pm</span></time>
        
      </p>
    
  </header>


<div class="entry-content"><p>本文所使用的环境是<strong>Ubuntu 14.04 32bit</strong>系统，<strong>Intel I5</strong>处理器，<strong>X86</strong>体系结构</p>

<h2 id="section">提出问题</h2>

<p>如果我说下面的程序存在性能问题，您信吗？</p>

<!--more-->

<div class="bogus-wrapper"><notextile><figure class="code"><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class="line-number">1</span>
<span class="line-number">2</span>
<span class="line-number">3</span>
<span class="line-number">4</span>
<span class="line-number">5</span>
<span class="line-number">6</span>
<span class="line-number">7</span>
<span class="line-number">8</span>
<span class="line-number">9</span>
<span class="line-number">10</span>
<span class="line-number">11</span>
<span class="line-number">12</span>
<span class="line-number">13</span>
<span class="line-number">14</span>
<span class="line-number">15</span>
<span class="line-number">16</span>
<span class="line-number">17</span>
<span class="line-number">18</span>
<span class="line-number">19</span>
<span class="line-number">20</span>
<span class="line-number">21</span>
<span class="line-number">22</span>
</pre></td><td class="code"><pre><code class="c++"><span class="line"><span class="cp">#include&lt;thread&gt;</span>
</span><span class="line"><span class="kt">int32_t</span> <span class="n">global</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span><span class="o">=</span><span class="p">{</span><span class="mi">0</span><span class="p">};</span>
</span><span class="line"><span class="kt">void</span> <span class="nf">f</span><span class="p">()</span>
</span><span class="line"><span class="p">{</span>
</span><span class="line">  <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="mi">100000000</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
</span><span class="line">    <span class="o">++</span><span class="n">global</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>
</span><span class="line">  <span class="p">}</span>
</span><span class="line"><span class="p">}</span>
</span><span class="line"><span class="kt">void</span> <span class="nf">g</span><span class="p">()</span>
</span><span class="line"><span class="p">{</span>
</span><span class="line">  <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="mi">100000000</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
</span><span class="line">    <span class="o">++</span><span class="n">global</span><span class="p">[</span><span class="mi">1</span><span class="p">];</span>
</span><span class="line">  <span class="p">}</span>
</span><span class="line"><span class="p">}</span>
</span><span class="line"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span>
</span><span class="line"><span class="p">{</span>
</span><span class="line">  <span class="n">std</span><span class="o">::</span><span class="kr">thread</span> <span class="n">thread1</span><span class="p">(</span><span class="n">f</span><span class="p">);</span>
</span><span class="line">  <span class="n">std</span><span class="o">::</span><span class="kr">thread</span> <span class="n">thread2</span><span class="p">(</span><span class="n">g</span><span class="p">);</span>
</span><span class="line">  <span class="n">thread1</span><span class="p">.</span><span class="n">join</span><span class="p">();</span>
</span><span class="line">  <span class="n">thread2</span><span class="p">.</span><span class="n">join</span><span class="p">();</span>
</span><span class="line">  <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
</span><span class="line"><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure></notextile></div>
<p>这个程序，在我的电脑上，运行时间为：</p>

<pre><code>real	0m0.822s
user	0m1.596s
sys     0m0.000s
</code></pre>

<h2 id="section-1">分析问题</h2>

<p>有人说，两个线程分别操作不同的计数器，这么完美的程序，会有性能问题？</p>

<p>答案是：有。</p>

<p>恩，原因在于大名鼎鼎的<strong>false sharing</strong>。如果您看过我以前写的<a href="http://www.yebangyu.org/blog/2015/10/18/hardwareanditshabit/">这篇</a>博客，应该还记得:现在的计算机一般由一个内存、一个<strong>CPU</strong>组成，而包含多个<strong>CPU Cores</strong>和<strong>Cache</strong>。如这幅图所示：</p>

<p><img src="http://7xnljs.com1.z0.glb.clouddn.com/cpuand%20cache.png" alt="memorycache" /></p>

<p><strong>cacheline</strong>是<strong>cache</strong>块单位，一个<strong>cacheline</strong>大小一般在<strong>32</strong>到<strong>256</strong>字节左右。<strong>cacheline</strong>是这张图中不同模块的数据交互元素。</p>

<p>在上面程序中，<strong>global</strong>是两个<strong>4</strong>字节变量构成的数组，大小为<strong>8</strong>字节，很可能被放到同一个<strong>cacheline</strong>里。当运行在<strong>CPU1 Core</strong>上的线程<strong>thread1</strong>修改了<strong>global[0]</strong>时，会让运行在<strong>CPU2 Core</strong>上对应<strong>global[0]</strong>和<strong>global[1]</strong>的<strong>cacheline</strong>失效，因此运行在<strong>CPU2 Core</strong>上的线程<strong>thread2</strong>修改<strong>global[1]</strong>时会发生<strong>cache miss</strong>。在它修改<strong>global[1]</strong>后，就让<strong>CPU1 Core</strong>中的<strong>cacheline</strong>失效。</p>

<p>很明显，这里面由于cacheline ping pong带来大量为了缓存一致性而产生的开销。</p>

<p>因此这种<strong>false sharing</strong>发生在多核、多线程环境中。单核或者单线程不会有<strong>false sharing</strong>问题。</p>

<p>遗憾的是，程序里存在这样的问题，并不容易通过肉眼发现。</p>

<p>幸运的是，这种问题一旦知道，就比较好解决。</p>

<h2 id="section-2">解决问题</h2>

<p>解决方法一：让这两个计数器间隔足够大，让它们不要在同一个<strong>cacheline</strong>里，不就行了么？</p>

<p>恩，定义一个<strong>global[10000]</strong>，然后线程<strong>1</strong>利用<strong>global[0]</strong>，线程<strong>2</strong>利用<strong>global[9999]</strong>，应该就可以了。</p>

<p>什么？这么愚蠢的方法都想得出来？接着往下看。</p>

<p>解决方法二：假如<strong>global</strong>不是一个数组呢？而是包含多个变量的结构体呢(这种情形也很常见)？上面的方法就不灵了吧？</p>

<p>恩，上面的方法不灵了，而且上面的方法太笨。网上有很多资料告诉您怎么定义变量让其<strong>cacheline aligned</strong>，这也是那些博客千篇一律的做法，不过还是值得在这里提及。</p>

<p>以gcc编译器为例：下面的做法不能保证global[0]和global[1]不在同一个cacheline里：</p>

<div class="bogus-wrapper"><notextile><figure class="code"><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class="line-number">1</span>
<span class="line-number">2</span>
</pre></td><td class="code"><pre><code class="c++"><span class="line"><span class="cp">#define CACHELINE_SIZE 64</span>
</span><span class="line"><span class="kt">int32_t</span> <span class="n">global</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="n">__attribute__</span><span class="p">((</span><span class="n">aligned</span><span class="p">(</span><span class="n">CACHELINE_SIZE</span><span class="p">)));</span>
</span></code></pre></td></tr></table></div></figure></notextile></div>
<p>这样只能保证global数组的首元素是cacheline对齐的，不能保证global[0]和global[1]不在同一个cacheline。</p>

<p>以下是正确做法：</p>
<div class="bogus-wrapper"><notextile><figure class="code"><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class="line-number">1</span>
<span class="line-number">2</span>
<span class="line-number">3</span>
<span class="line-number">4</span>
<span class="line-number">5</span>
<span class="line-number">6</span>
</pre></td><td class="code"><pre><code class="c++"><span class="line"><span class="cp">#define CACHELINE_SIZE 64</span>
</span><span class="line"><span class="k">struct</span> <span class="n">MyCounter</span>
</span><span class="line"><span class="p">{</span>
</span><span class="line">  <span class="kt">int32_t</span> <span class="n">counter</span><span class="p">;</span>
</span><span class="line"><span class="p">}</span><span class="n">__attribute__</span><span class="p">((</span><span class="n">aligned</span> <span class="p">(</span><span class="n">CACHELINE_SIZE</span><span class="p">)));</span>
</span><span class="line"><span class="n">MyCounter</span> <span class="n">global</span><span class="p">[</span><span class="mi">2</span><span class="p">];</span>
</span></code></pre></td></tr></table></div></figure></notextile></div>

<p>还有没有其他方法？有。接着往下看。</p>

<p>解决方法三：重点来了。</p>

<p>我们其实可以在线程里使用局部变量！</p>

<div class="bogus-wrapper"><notextile><figure class="code"><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class="line-number">1</span>
<span class="line-number">2</span>
<span class="line-number">3</span>
<span class="line-number">4</span>
<span class="line-number">5</span>
<span class="line-number">6</span>
<span class="line-number">7</span>
<span class="line-number">8</span>
<span class="line-number">9</span>
<span class="line-number">10</span>
<span class="line-number">11</span>
<span class="line-number">12</span>
<span class="line-number">13</span>
<span class="line-number">14</span>
<span class="line-number">15</span>
<span class="line-number">16</span>
<span class="line-number">17</span>
<span class="line-number">18</span>
<span class="line-number">19</span>
<span class="line-number">20</span>
<span class="line-number">21</span>
<span class="line-number">22</span>
<span class="line-number">23</span>
<span class="line-number">24</span>
<span class="line-number">25</span>
<span class="line-number">26</span>
</pre></td><td class="code"><pre><code class="c++"><span class="line"><span class="cp">#include&lt;thread&gt;</span>
</span><span class="line"><span class="kt">int32_t</span> <span class="n">global</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span><span class="mi">0</span><span class="p">};</span>
</span><span class="line"><span class="kt">void</span> <span class="nf">f</span><span class="p">()</span>
</span><span class="line"><span class="p">{</span>
</span><span class="line">  <span class="kt">int</span> <span class="n">counter1</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span><span class="line">  <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="mi">100000000</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
</span><span class="line">    <span class="o">++</span><span class="n">counter1</span><span class="p">;</span>
</span><span class="line">  <span class="p">}</span>
</span><span class="line">  <span class="n">global</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="n">counter1</span><span class="p">;</span>
</span><span class="line"><span class="p">}</span>
</span><span class="line"><span class="kt">void</span> <span class="nf">g</span><span class="p">()</span>
</span><span class="line"><span class="p">{</span>
</span><span class="line">  <span class="kt">int</span> <span class="n">counter2</span> <span class="o">=</span><span class="mi">0</span><span class="p">;</span>
</span><span class="line">  <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="mi">100000000</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
</span><span class="line">    <span class="o">++</span><span class="n">counter2</span><span class="p">;</span>
</span><span class="line">  <span class="p">}</span>
</span><span class="line">  <span class="n">global</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="n">counter2</span><span class="p">;</span>
</span><span class="line"><span class="p">}</span>
</span><span class="line"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span>
</span><span class="line"><span class="p">{</span>
</span><span class="line">  <span class="n">std</span><span class="o">::</span><span class="kr">thread</span> <span class="n">thread1</span><span class="p">(</span><span class="n">f</span><span class="p">);</span>
</span><span class="line">  <span class="n">std</span><span class="o">::</span><span class="kr">thread</span> <span class="n">thread2</span><span class="p">(</span><span class="n">g</span><span class="p">);</span>
</span><span class="line">  <span class="n">thread1</span><span class="p">.</span><span class="n">join</span><span class="p">();</span>
</span><span class="line">  <span class="n">thread2</span><span class="p">.</span><span class="n">join</span><span class="p">();</span>
</span><span class="line">  <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
</span><span class="line"><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure></notextile></div>
<p><strong>counter1</strong>和<strong>counter2</strong>在自己的线程栈上，<strong>cacheline</strong>位于对应的<strong>CPU core</strong>里，大家相安无事。只有执行第<strong>9</strong>行和第<strong>17</strong>行时代价可能高点。</p>

<p>这个程序，在我的电脑上运行时间为：</p>

<pre><code>real	0m0.293s
user	0m0.580s
sys     0m0.000s
</code></pre>

<p>解决方法四：</p>

<p><strong>global</strong>神马变量？全局变量。<strong>counter1/counter2</strong>神马变量？局部变量。</p>

<p>有没有一种东东，既有全局的性质，又有局部的效果（线程私有）呢？</p>

<p>恩，如果您看过我以前写的<a href="http://www.yebangyu.org/blog/2015/10/31/linux-parallen-programmming-infrastructure/">这篇</a>博客，就不会对<strong>__thread</strong>感到陌生。对！提供强大<strong>scalability</strong>的利器，就是它了！</p>

<div class="bogus-wrapper"><notextile><figure class="code"><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class="line-number">1</span>
<span class="line-number">2</span>
<span class="line-number">3</span>
<span class="line-number">4</span>
<span class="line-number">5</span>
<span class="line-number">6</span>
<span class="line-number">7</span>
<span class="line-number">8</span>
<span class="line-number">9</span>
<span class="line-number">10</span>
<span class="line-number">11</span>
<span class="line-number">12</span>
<span class="line-number">13</span>
<span class="line-number">14</span>
<span class="line-number">15</span>
<span class="line-number">16</span>
<span class="line-number">17</span>
<span class="line-number">18</span>
<span class="line-number">19</span>
<span class="line-number">20</span>
<span class="line-number">21</span>
<span class="line-number">22</span>
</pre></td><td class="code"><pre><code class="c++"><span class="line"><span class="cp">#include&lt;thread&gt;</span>
</span><span class="line"><span class="n">__thread</span> <span class="kt">int</span> <span class="n">counter</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span><span class="line"><span class="kt">void</span> <span class="nf">f</span><span class="p">()</span>
</span><span class="line"><span class="p">{</span>
</span><span class="line">  <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="mi">100000000</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
</span><span class="line">    <span class="o">++</span><span class="n">counter</span><span class="p">;</span>
</span><span class="line">  <span class="p">}</span>
</span><span class="line"><span class="p">}</span>
</span><span class="line"><span class="kt">void</span> <span class="nf">g</span><span class="p">()</span>
</span><span class="line"><span class="p">{</span>
</span><span class="line">  <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="mi">100000000</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
</span><span class="line">    <span class="o">++</span><span class="n">counter</span><span class="p">;</span>
</span><span class="line">  <span class="p">}</span>
</span><span class="line"><span class="p">}</span>
</span><span class="line"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span>
</span><span class="line"><span class="p">{</span>
</span><span class="line">  <span class="n">std</span><span class="o">::</span><span class="kr">thread</span> <span class="n">thread1</span><span class="p">(</span><span class="n">f</span><span class="p">);</span>
</span><span class="line">  <span class="n">std</span><span class="o">::</span><span class="kr">thread</span> <span class="n">thread2</span><span class="p">(</span><span class="n">g</span><span class="p">);</span>
</span><span class="line">  <span class="n">thread1</span><span class="p">.</span><span class="n">join</span><span class="p">();</span>
</span><span class="line">  <span class="n">thread2</span><span class="p">.</span><span class="n">join</span><span class="p">();</span>
</span><span class="line">  <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
</span><span class="line"><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure></notextile></div>

<p>这个程序在我的电脑上的运行时间为：</p>

<pre><code>real	0m0.325s
user	0m0.644s
sys     0m0.000s
</code></pre>

<p>不过其他线程如何读取到每个计数线程的<strong>counter</strong>呢？不难，但是也不是那么简单，背后涉及到很多问题（其实本文最大的目的是通过<strong>false sharing</strong>，揭示<strong>partition</strong>这种并发编程里最大的设计原则）。我们下次专门聊。</p>

<h2 id="section-3">附录</h2>

<p>1，编译以上多线程程序的时候，请使用：</p>

<pre><code>g++ -pthread -std=c++11 xxx.cpp
</code></pre>

<p>如果没有指定<code>-pthread</code>，那么程序可以编译链接通过，运行时报错：</p>

<p>terminate called after throwing an instance of ‘std::system_error’</p>

<p>what():  Enable multithreading to use std::thread: Operation not permitted</p>

<p>Aborted (core dumped)</p>

<p>2，程序计时我用的是 <code>time ./a.out</code>的方式。</p>

<h2 id="section-4">致谢</h2>

<p>本文发出后，微博网友@Debin_IIE指出了一个笔误。非常感谢。</p>
</div>


  <footer>
    <p class="meta">
      
  

<span class="byline author vcard">Posted by <span class="fn">Yebangyu</span></span>

      




<time class='entry-date' datetime='2015-12-30T23:06:12+08:00'><span class='date'><span class='date-month'>Dec</span> <span class='date-day'>30</span><span class='date-suffix'>th</span>, <span class='date-year'>2015</span></span> <span class='time'>11:06 pm</span></time>
      

<span class="categories">
  
    <a class='category' href='/blog/categories/bing-xing-bian-cheng/'>并行编程</a>
  
</span>


    </p>
    
      <div class="sharing">
  
  
  
</div>

    
    <p class="meta">
      
        <a class="basic-alignment left" href="/blog/2015/12/26/aprogrammersclock/" title="Previous Post: 程序员时钟解读">&laquo; 程序员时钟解读</a>
      
      
        <a class="basic-alignment right" href="/blog/2016/01/07/timingcprograminlinux/" title="Next Post: Linux下C++程序计时方法">Linux下C++程序计时方法 &raquo;</a>
      
    </p>
  </footer>
</article>


</div>

<aside class="sidebar">
  
    <section>
  <h1>Recent Posts</h1>
  <ul id="recent_posts">
    
      <li class="post">
        <a href="/blog/2017/03/11/2017/">2017技术成长之路</a>
      </li>
    
      <li class="post">
        <a href="/blog/2017/02/17/virtualfunctionandvariadicparametertemplate/">虚函数和变长参数模板的妙用</a>
      </li>
    
      <li class="post">
        <a href="/blog/2016/12/25/singleton/">Singleton与多线程</a>
      </li>
    
      <li class="post">
        <a href="/blog/2016/12/04/introductiontohazardpointer/">Lock Free中的Hazard Pointer(下)</a>
      </li>
    
      <li class="post">
        <a href="/blog/2016/12/03/gccandperfopt/">性能优化的那些传说和迷思</a>
      </li>
    
  </ul>
</section>
<section>
  <h1>Friends' Link</h1>
  <ul>
    <li>
	  <li><a href="http://www.chongh.wiki/">Diting0x</a></li>
	  <li><a href="http://www.xiaolili.net/">wangli</a></li>
	  <li><a href="http://www.skykewei.top">dukewei</a></li>
	  <li><a href="http://irwenqiang.github.io">chenwenqiang</a></li>
      <li><a href="http://www.armsword.com">duruofei</a></li>
    </li>
  </ul>
</section><section>
  <h1>Yebangyu</h1>
  <p>福建人。热爱历史、K歌、NBA</p>
  <p>帝都码农</p>
  <p>历史学家，专治秦汉史</p>
</section>
<section>
 <h1>Categories</h1>
 <ul id="categories">
  <li class='category'><a href='/blog/categories/c-plus-plus/'>c++ (11)</a></li>
<li class='category'><a href='/blog/categories/soupen/'>soupen (4)</a></li>
<li class='category'><a href='/blog/categories/web/'>web (1)</a></li>
<li class='category'><a href='/blog/categories/qi-ta/'>其他 (5)</a></li>
<li class='category'><a href='/blog/categories/li-shi/'>历史 (2)</a></li>
<li class='category'><a href='/blog/categories/bing-xing-bian-cheng/'>并行编程 (20)</a></li>
<li class='category'><a href='/blog/categories/xing-neng-you-hua/'>性能优化 (2)</a></li>
<li class='category'><a href='/blog/categories/suan-fa/'>算法 (4)</a></li>
<li class='category'><a href='/blog/categories/bian-yi-lian-jie/'>编译链接 (2)</a></li>

 </ul>
</section>




  
</aside>


    </div>
  </div>
  <footer role="contentinfo"><!-- mathjax config similar to math.stackexchange -->
<script type="text/x-mathjax-config">
MathJax.Hub.Config({
  jax: ["input/TeX", "output/HTML-CSS"],
  tex2jax: {
    inlineMath: [ ['$', '$'] ],
    displayMath: [ ['$$', '$$']],
    processEscapes: true,
    skipTags: ['script', 'noscript', 'style', 'textarea', 'pre', 'code']
  },
  messageStyle: "none",
  "HTML-CSS": { preferredFont: "TeX", availableFonts: ["STIX","TeX"] }
});
</script>
<script src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_HTML" type="text/javascript"></script>
<p>
  Copyright &copy; 2017 - Yebangyu -
  <span class="credit">Powered by <a href="http://octopress.org">Octopress</a></span>
</p>
<script type="text/javascript">var cnzz_protocol = (("https:" == document.location.protocol) ? " https://" : " http://");document.write(unescape("%3Cspan id='cnzz_stat_icon_1257548193'%3E%3C/span%3E%3Cscript src='" + cnzz_protocol + "s11.cnzz.com/z_stat.php%3Fid%3D1257548193' type='text/javascript'%3E%3C/script%3E"));</script>

</footer>
  











</body>
</html>
